<template>
  <div class="normal-content border-box">
    <div class="content d-flex flex-column h-100">
      <header class="pt-2"
              style="font-size:0">
        <!-- 此处font-isze设置为0 ，目的是为了 filterbar 在使用 d-inline-block 样式的时候，不会造成产生空白间隙 -->
        <div v-if="title"
             class="mb-2">
          <span class="fs-5 lh-lg fw-semibold text-secondary">
            <ju-icon class="mx-1 align-text-bottom"
                     icon="geo-alt-fill"
                     svg-icon></ju-icon>
            {{ title }}
          </span>
        </div>
        <div v-if="hasFilterbar"
             class="filterbar border-box rounded shadow-sm mb-2"
             :class="{'is-opened':showFilter,'d-inline-block':!showFilter}">
          <div class="p-2 pb-0 filterbar-panel"
               :class="{ 'shadow':showFilter, 'rounded':showFilter }">
            <el-form ref="frmFilter"
                     inline
                     :model="syncedFilter">
              <transition enter-active-class="animate__animated animate__zoomIn "
                          leave-active-class="animate__animated animate__zoomOut ">
                <el-button v-if="filterPanelHeight > 53"
                           class="more-filter-button align-top float-end"
                           style="--animate-duration: .2s"
                           type="text"
                           @click.stop="showFilter = !showFilter">
                  <div>
                    <span v-if="showFilter">收起</span>
                    <span v-else>展开</span>
                    <br />
                    <span v-if="showFilter">面板</span>
                    <span v-else>更多</span>
                  </div>
                  <div class="more-filter-button-icon position-absolute top-0 d-flex align-items-center justify-content-center">
                    <ju-icon icon="el-icon-caret-top"
                             :rotate="showFilter ? 'up' : 'down'" />
                  </div>
                </el-button>
              </transition>
              <el-button class="ms-0 align-top float-end "
                         :class="{'me-2':filterPanelHeight > 53}"
                         round
                         type="warning"
                         @click.stop="doResetFilter">
                <ju-icon icon="recycle"
                         svg-icon></ju-icon>
                重置
              </el-button>
              <slot name="filterbar"></slot>
            </el-form>
            <!-- 不给高度就不会触发高度变化时产生的resize -->
            <iframe seamless
                    style="top:0;left:0;width:100%;position:absolute;z-index:-1;border:none;box-sizing:border-box;visibility:hidden;opacity:0;pointer-events:none"
                    @load="bindFilterPanelResize"></iframe>
          </div>
        </div>
        <div class="toolbar clearfix">
          <slot name="toolbar"></slot>
          <template v-if="hasMoreToolbar">
            <el-popover v-if="$slots['more-toolbar'].length > 5"
                        placement="top"
                        :popper-class="['border','border-dark',$style.moreToolbarPopover]"
                        trigger="manual"
                        v-model="moreToolbarVisiable">
              <el-button slot="reference"
                         class="align-top me-2 mb-2"
                         :disabled="!checkRows.length"
                         type="info"
                         @click.stop="moreToolbarVisiable = !moreToolbarVisiable">
                批量操作
                <ju-icon class="ms-1"
                         icon="three-dots"
                         svg-icon></ju-icon>
              </el-button>
              <div class="py-1 mb-1 pe-2 d-flex">
                <div><b class="me-1">批量操作：</b>已选中 <span class="text-danger">{{ checkRows.length }}</span> 条数据</div>
                <el-link class="ms-auto"
                         type="danger"
                         :underline="false"
                         @click.stop="moreToolbarVisiable = false">
                  <ju-icon icon="x-lg"
                           svg-icon></ju-icon>
                </el-link>
              </div>
              <div class="more-toolbar">
                <slot name="more-toolbar"></slot>
              </div>
            </el-popover>
            <template v-else>
              <span v-if="$slots.toolbar?.length"
                    class="el-divider el-divider--vertical"
                    style="font-size:1rem">
              </span>
              <slot name="more-toolbar"></slot>
            </template>
          </template>
          <div class="float-end right text-end">
            <div class=" align-middle d-inline-flex align-items-stretch ipt-search float-start mb-2">
              <el-input clearable
                        placeholder="关键字"
                        prefix-icon="el-icon-search"
                        @keyup.enter.native="onSearch"
                        v-model="syncedFilter.searchKey">
              </el-input>
              <el-button class="rounded-start-pill"
                         :class="{'rounded-end-pill':!hasFilterbar}"
                         :style="hasFilterbar ? '' : 'margin-right:1px'"
                         type="primary"
                         @click.stop="onSearch">查询</el-button>
              <el-button v-if="hasFilterbar"
                         class="ms-0 rounded-end-pill ipt-search-filter"
                         :disabled="filterPanelHeight <= 53"
                         type="primary"
                         @click.stop="showFilter = true">
                <ju-icon class="align-bottom"
                         icon="funnel-fill"
                         svg-icon></ju-icon>
              </el-button>
            </div>
            <ju-auth :auth="showExport">
              <el-tooltip content="导出"
                          placement="top">
                <el-button round
                           type="warning"
                           @click.stop="ExportDataDialog.show = true">
                  <ju-icon icon="box-arrow-up-right"
                           svg-icon></ju-icon>
                </el-button>
              </el-tooltip>
            </ju-auth>
            <el-tooltip content="设置"
                        placement="top">
              <el-button round>
                <ju-icon icon="gear-fill"
                         svg-icon></ju-icon>
              </el-button>
            </el-tooltip>
          </div>
          <el-tooltip placement="top">
            <div slot="content"
                 class="text-center">
              刷新数据<br />
              上次刷新时间：<span class="text-warning">{{ lastRefreshTime | formatTime("HH:mm:ss") }}</span>
            </div>
            <el-button class="float-start"
                       :disabled="syncedTableOptions.loading"
                       round
                       @click="onSearch">
              <ju-icon icon="el-icon-refresh"></ju-icon>
            </el-button>
          </el-tooltip>
        </div>
      </header>
      <main class="flex-1 table-wrap shadow-sm rounded-1"
            element-loading-custom-class="dark"
            element-loading-spinner="el-icon-loading"
            element-loading-text="拼命加载中"
            v-loading="syncedTableOptions.loading">
        <vxe-table ref="tbl"
                   :id="cacheId"
                   align="center"
                   auto-resize
                   class="normal-content-table"
                   :column-config="{resizable: true}"
                   :custom-config="{storage:{resizable:cacheId}}"
                   :data="syncedTableOptions.data"
                   height="auto"
                   :mouse-config="{selected:true}"
                   :resizable-config="{minWidth:40}"
                   round
                   :row-config="{isHover: true,isCurrent: true,keyField:syncedTableOptions.rowKey }"
                   :scroll-y="{gt: 101,scrollToTopOnChange:true}"
                   show-header-overflow="tooltip"
                   show-overflow="tooltip"
                   :sort-config="{trigger: 'cell'}"
                   stripe
                   @cell-dblclick="({row, column, $event}) => $emit('row-dblclick',row, column, $event)"
                   @cell-selected="onCellSelected"
                   @checkbox-all="({records}) => onSelectionChange(records)"
                   @checkbox-change="({records}) => onSelectionChange(records)"
                   @checkbox-range-end="({records}) => onSelectionChange(records)"
                   @current-change="doCurrentChange">
          <vxe-column fixed="left"
                      :resizable="false"
                      :show-header-overflow="false"
                      :show-overflow="false"
                      type="seq"
                      width="40"></vxe-column>
          <vxe-column fixed="left"
                      :resizable="false"
                      :show-header-overflow="false"
                      :show-overflow="false"
                      type="checkbox"
                      width="40"></vxe-column>
          <slot></slot>
          <vxe-column :resizable="false"
                      :show-header-overflow="false"
                      :show-overflow="false"></vxe-column>
          <template #empty>
            <el-empty class="p-0"
                      description="暂无数据">
              <el-button round
                         type="primary"
                         @click.stop="onSearch">
                <ju-icon class="me-1 align-bottom"
                         icon="el-icon-refresh"></ju-icon>
                刷新重试
              </el-button>
            </el-empty>
          </template>
        </vxe-table>
      </main>
      <footer class="tablebar py-2 d-flex align-items-center">
        <div>
          <el-button :disabled="syncedTableOptions.loading || !currentRow"
                     type="text"
                     @click.stop="setCurrentRow(currentRow)">
            <ju-icon class="me-1"
                     icon="record-circle"
                     svg-icon></ju-icon>定位
          </el-button>
          <!-- <el-button :disabled="syncedTableOptions.loading"
                     type="text">
            <ju-icon class="me-1"
                     icon="el-icon-s-opportunity"></ju-icon>使用技巧
          </el-button> -->
        </div>
        <el-pagination background
                       class="ms-auto"
                       :current-page.sync="syncedTableOptions.currentPage"
                       :disabled="syncedTableOptions.loading"
                       :layout="pageLayout"
                       :page-size.sync="syncedTableOptions.pageSize"
                       :page-sizes="syncedTableOptions.pageSizes"
                       :total="syncedTableOptions.total">
        </el-pagination>
      </footer>
    </div>
    <dialog-export-data :row-checked-count="checkRows.length"
                        :visible.sync="ExportDataDialog.show"
                        @command="command => $emit('command',command)">
    </dialog-export-data>
  </div>
</template>

<script lang="ts">
  import { Component, Emit, NoCache, Prop, PropSync, Vue, Watch } from "@some21/vue-class-decorator";
  import { cloneDeep, debounce } from "lodash";
  import dayjs from "dayjs";
  import { createFilterData, createTableOptions } from "@/framework/models/TableOptions";

  @Component({
    components: {
      DialogExportData: () => import("./Dialogs/DialogExportData.vue"),
    },
    name: "NormalContent",
  })
  export default class extends Vue {
    $refs: {
      tbl: any;
    };

    private __DEF_FILTER__ = null;

    ExportDataDialog = {
      show: false,
    };

    showFilter = false;
    currentRow = null;
    checkRows = [];

    @Emit("selection-change")
    onSelectionChange(records) {
      this.checkRows = records || [];
      if (this.checkRows.length) {
        this.moreToolbarVisiable = true;
      } else {
        this.moreToolbarVisiable = false;
      }
    }

    lastRefreshTime = new Date(); //TODO: 目前初始化的时间不是特别精准，将来优化

    @NoCache
    get hasFilterbar() {
      return this.$slots.filterbar && this.$slots.filterbar.length;
    }
    @NoCache
    get hasToolbar() {
      return this.$slots.toolbar && this.$slots.toolbar.length;
    }

    // 手动控制批量操作的 popover 的显示
    moreToolbarVisiable = false;
    @NoCache
    get hasMoreToolbar() {
      return this.$slots["more-toolbar"] && this.$slots["more-toolbar"].length;
    }

    onSearch() {
      // 判断上次刷新时间和本次操作刷新时间间隔是否小于N 秒，若小于N秒，则提示限流
      // 若为翻页操作，则不触发限流提示
      // 阀值暂定 1.5 秒，依据实际情况进行调整
      const threshold = 1.2;
      if (this.lastRefreshTime && dayjs().diff(this.lastRefreshTime, "seconds", true) <= threshold) {
        this.$message.warning({ message: "您的操作太快啦，喝口水休息下吧！", showClose: true });
        return;
      }
      this.lastRefreshTime = new Date();

      this.$emit("command", "search", this.syncedFilter);
    }

    @Prop({ type: String })
    cacheId: string;
    @PropSync("filter", { type: Object, default: createFilterData() })
    syncedFilter: ReturnType<typeof createFilterData>;
    @PropSync("tblOptions", { type: Object, default: createTableOptions() })
    syncedTableOptions: ReturnType<typeof createTableOptions>;
    @Prop({ type: Array, default: [] })
    unselCols: string[];
    @Prop({ type: String, default: "total, sizes, prev, pager, next, jumper" })
    pageLayout: string;
    @Prop({ type: String })
    title: string;
    @Prop({ type: Boolean, default: true })
    showExport: boolean;

    @Watch("tblOptions.data")
    onTableDataChange(value) {
      if (!value) {
        console.warn("禁止将 tblOptions.data 设置为null！请检查数据是否存在错误？");
        //! 修复当把data 设置为null 的时候，会导致多次触发tblOptions变化而产生的影响
        this.syncedTableOptions.data = [];
      }
    }
    @Watch("tblOptions.currentPage")
    @Watch("tblOptions.pageSize")
    onPageInfoChange() {
      // 防止将参数设置为 null时候发生异常
      if (this.syncedTableOptions.currentPage && this.syncedTableOptions.pageSize) {
        this.currentRow = null;
        this.onSelectionChange([]);
        this.$emit("page-change");
      } else {
        console.warn("请检查为什么会把tblOptions.currentPage或者syncedTableOptions.pageSize设置为空值？");
      }
    }

    filterPanelHeight = 48;

    bindFilterPanelResize(evt) {
      const parentElm = evt.target.parentElement;

      const onOffsetHeightChange = debounce(async () => {
        await Vue.nextTick();
        this.filterPanelHeight = parentElm.offsetHeight;
        if (this.filterPanelHeight <= 53) {
          this.showFilter = false;
        }
      }, 100);

      this.filterPanelHeight = parentElm.offsetHeight; // 初次绑定时候，获取一次高度
      (evt.target.contentWindow as Window).addEventListener("resize", () => {
        onOffsetHeightChange();
      });
    }

    activated() {
      const threshold = 60;
      //! 如果回到这个页面后的时间超过了阀值的时间，则进行刷新操作
      if (this.lastRefreshTime && dayjs().diff(this.lastRefreshTime, "seconds", true) >= threshold) {
        this.$emit("command", "search", this.syncedFilter);
      }
    }

    created() {
      this.__DEF_FILTER__ = cloneDeep({ ...createFilterData(), ...this.syncedFilter }); // 深拷贝
      this.doResetFilter();
      this.syncedTableOptions = { ...createTableOptions(), ...this.syncedTableOptions };
    }
    // 单元格选中时候的处理
    onCellSelected({ column }) {
      if (
        ["checkbox", "seq", "radio"].includes(column.type) ||
        column.title === "操作" ||
        !column.title ||
        (column.field && this.unselCols.includes(column.field))
      ) {
        this.$refs.tbl.clearSelected();
      }
    }
    // 重置筛选条件
    doResetFilter() {
      this.syncedFilter = cloneDeep(this.__DEF_FILTER__);
      this.$emit("command", "search");
    }
    doCurrentChange({ newValue, oldValue }) {
      this.currentRow = newValue;
      this.$emit("current-change", newValue, oldValue);
    }
    setCurrentRow(row) {
      this.$refs.tbl.scrollToRow(row);
      this.$refs.tbl.setCurrentRow(row);
      this.currentRow = row;
    }
    async doLayout() {
      await this.$refs.tbl.recalculate();
    }
  }
</script>

<style lang="scss" module>
  .more-toolbar-popover {
    padding: 0.5rem 0 0 0.5rem;
    max-width: 100%;
  }
</style>

<style lang="scss" scoped>
  .btn-refresh {
    padding-left: 10px;
    padding-right: 10px;
  }
  .more-filter-button {
    padding: 3px;
    position: relative;
    overflow: hidden;
    .more-filter-button-icon {
      position: absolute;
      top: 0;
      left: 100%;
      width: 100%;
      height: 100%;
      background: rgba(0, 0, 0, 0.6);
      color: #fff;
      border-radius: 3px;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: all 0.1s;
      font-size: 1.5em;
    }
    &:hover .more-filter-button-icon {
      left: 0;
    }
  }
  .el-pagination :deep {
    .el-pagination__sizes {
      margin: 0;
    }
    .el-pagination__sizes .el-input__inner,
    .el-pagination__jump .el-input__inner {
      border-radius: 50em;
    }
    .btn-prev {
      border-top-left-radius: 50em;
      border-bottom-left-radius: 50em;
    }
    .btn-next {
      border-top-right-radius: 50em;
      border-bottom-right-radius: 50em;
    }
  }

  .filterbar {
    overflow: hidden;
    height: 48px;
    overflow: hidden;
    transition: height 0.2s;
    position: relative;
    .ipt-search {
      width: 200px;
    }
    .filterbar-panel {
      background: #fff;
      transition: all 0.2s;
      overflow: hidden;
    }
    .filterbar-panel-button {
      padding-left: 9px;
      padding-right: 9px;
    }
    &.is-opened {
      overflow: visible;
      z-index: 50;

      .filterbar-panel {
        overflow: auto;
      }
    }
  }
  .tablebar {
    font-size: 13px;
  }

  .table-wrap {
    display: block;
    flex-basis: auto !important;
    overflow: hidden; // 不能移除，否则表格高度无法自适应，会撑开该容器
  }

  .toolbar {
    > :deep(:not(.right)),
    .right > :deep(*) {
      // margin-right: 0.25rem;
      // margin-left: 0.25rem;
      margin-bottom: 0.5rem;
      vertical-align: middle;
    }
    > :deep(:not(.right)) {
      margin-right: 0.5rem;
      margin-left: 0;
    }
    .right > :deep(*) {
      margin-left: 0.5rem;
    }
    .el-button--small.is-round {
      padding: 7.5px;
      font-size: 15px;
    }

    .ipt-search {
      width: 260px;
      border-top-left-radius: 50rem;
      border-bottom-left-radius: 50rem;
      border-top-right-radius: 50rem;
      border-bottom-right-radius: 50rem;
      background-color: #fff;
      box-shadow: 1px 1px 0px inset rgba(var(--theme-primary-rgb), 0.2);
      border: 1px solid var(--theme-primary);
      box-sizing: border-box;

      :deep(.el-input__inner) {
        border: none;
        background-color: transparent;
        border-top-left-radius: 50rem;
        border-bottom-left-radius: 50rem;
        border-top-right-radius: 0;
        border-bottom-right-radius: 0;
      }
      > .el-button {
        padding-top: 7px;
        padding-bottom: 7px;
        margin-top: 1px;
        margin-bottom: 1px;

        &.ipt-search-filter {
          margin-right: 1px;
          position: relative;
          padding-left: 12px;
          padding-right: 12px;
          &::before {
            content: " " !important;
            position: absolute;
            transition: all 0.2s;
            left: -0.5px;
            top: 3px;
            bottom: 3px;
            font-size: 0;
            border-left: 1px solid;
            border-image: linear-gradient(rgba(var(--theme-primary-rgb), 0), rgba(255, 255, 255, 0.8), rgba(var(--theme-primary-rgb), 0)) 1;
          }
        }
      }
    }
  }

  .more-toolbar {
    > :deep(*) {
      margin-left: 0;
      margin-right: 0.5rem;
      margin-bottom: 0.5rem;
    }
  }

  .normal-content-table :deep {
    // 给序号行加上纵向颜色条的填充
    .vxe-table--body-wrapper.fixed-left--wrapper::before,
    .vxe-table--body-wrapper.body--wrapper::before {
      content: " ";
      display: initial !important; // 好像固定左侧栏和本身有冲突，不清楚vxe-table 不让用的原因是什么
      position: absolute;
      left: 0;
      top: 0;
      bottom: 0;
      width: 40px;
      background: var(--theme-primary);
    }
    &.border--full {
      .vxe-table--body-wrapper.fixed-left--wrapper::before,
      .vxe-table--body-wrapper.body--wrapper::before {
        border-right: 1px solid var(--theme-white);
      }
    }

    // .vxe-table--render-default
    &.is--round.is--header:not(.is--footer) .vxe-table--body-wrapper.fixed-left--wrapper {
      border-radius: 0;
    }

    // .vxe-table--fixed-left-wrapper.scrolling--middle {
    //   border-right: 1px solid rgba(var(--theme-primary-rgb), 0.2);
    // }
  }
</style>
